﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace IRCClient
{
    /// <summary>
    /// Klasi sem sér um DCC tengingu.
    /// </summary>
	class DCC
	{
		string fileName;
		IPAddress target;
		TcpClient tcpClient;
		NetworkStream stream;
		int bytesReceived = 0;
		long totalBytes = 0;
		long fileSize = 0;
		byte[] buffer = new byte[1024];
		FileStream file;
		DccSpeed speed;
		public string error;

        /// <summary>
        /// Smiður sem upphafsstillir meðlimabreytur.
        /// </summary>
        /// <param name="IP">Upphafsstillir host ip addressuna.</param>
        /// <param name="fileName">Upphafsstillir skráar nafnið.</param>
        /// <param name="fileSize">Upphafsstillir stærðina á skránni.</param>
		public DCC(string IP, string fileName, int fileSize)
		{
			this.fileName = fileName;
			this.target = IPAddress.Parse(IP);
			this.fileSize = fileSize;
			this.error = "";
			this.speed = DccSpeed.Rfc;
			UInt32 ip = UInt32.Parse(IP);
			UInt32 hostToNetworkOrder = (UInt32)IPAddress.HostToNetworkOrder((Int32)ip);

            //Búa til nýja file straum til geta tekið á móti skrá.
			file = new FileStream(fileName, FileMode.Create, FileAccess.Write);

            //Búa til tcp client.
			tcpClient = new TcpClient();
            
            //Búa til tengingu á milli með addressu og skráarstærð.
			tcpClient.Connect(new IPAddress(hostToNetworkOrder), 1024);

			stream = tcpClient.GetStream();

            //Kallar í fall sem sér um að móttaka skránna.
			Receive();
		}

		/// <summary>
		/// Fall sem sér um að taka á móti skránni.
		/// </summary>
		private void Receive()
		{
            //Á meðan að skráar stærðin er stærri en heildar byte-in sem tekið hefur verið á móti.
			try
			{
				while (fileSize > totalBytes && tcpClient.Connected)
				{
					//Lesa í buffer frá straumnum.
					bytesReceived = stream.Read(buffer, 0, 1024);

					//Skrifa í skrá það sem kom frá buffernum.
					file.Write(buffer, 0, bytesReceived);
					file.Flush();
					totalBytes += bytesReceived;
					// Senda ACK ef notaður er gamli staðallinn
					if (speed == DccSpeed.Rfc && tcpClient.Connected)
						stream.Write(getAck(totalBytes), 0, 4);
				}
			}
			catch (IOException) { }
			
			DateTime now = DateTime.Now;

			// Ef það var villa í sendingu
			if (fileSize < totalBytes)
			{
				Console.WriteLine("[{0}] Transfer unsuccessful.\n Filename: {1}. Received: {2} kB. Error message sent to sender.", now.ToLongTimeString(), fileName, (decimal)(totalBytes / 1024));
				this.error = "The transfer was unsuccessful. File: " + fileName + " Received: " + (decimal)(totalBytes / 1024) + " kB";
			}
			else
				Console.WriteLine("[{0}] Transfer successful.\n Filename: {1}. Size: {2} kB", now.ToLongTimeString(), fileName, (decimal)(totalBytes / 1024));
			
            file.Close();
			stream.Close();
			tcpClient.Close();
		}

		private byte[] getAck(long SentBytes)
		{
			byte[] acks = new byte[4];
			acks[0] = (byte)((SentBytes >>24 ) % 256);
			acks[1] = (byte)((SentBytes >>16 ) % 256);
			acks[2] = (byte)((SentBytes >>8  ) % 256);
			acks[3] = (byte)((SentBytes      ) % 256);
			return acks;
		}
	}
}
